2 位追蹤者

模組

模組是自我包含的軟體單元,由模型視圖控制器和其他支援組件組成。當模組安裝在應用程式中時,終端使用者可以存取模組的控制器。由於這些原因,模組通常被視為迷你應用程式。模組與應用程式的不同之處在於模組不能單獨部署,並且必須駐留在應用程式中。

建立模組

模組的組織形式是一個目錄,稱為模組的基底路徑。在該目錄中,有子目錄,例如 controllersmodelsviews,它們像在應用程式中一樣,包含控制器、模型、視圖和其他程式碼。以下範例顯示模組內的內容

forum/
    Module.php                   the module class file
    controllers/                 containing controller class files
        DefaultController.php    the default controller class file
    models/                      containing model class files
    views/                       containing controller view and layout files
        layouts/                 containing layout view files
        default/                 containing view files for DefaultController
            index.php            the index view file

模組類別

每個模組都應該有一個唯一的模組類別,它繼承自 yii\base\Module。該類別應該直接位於模組的基底路徑下,並且應該是可自動載入的。當存取模組時,將會建立相應模組類別的單一實例。與應用程式實例類似,模組實例用於在模組內的程式碼之間共享資料和組件。

以下是一個模組類別的範例

namespace app\modules\forum;

class Module extends \yii\base\Module
{
    public function init()
    {
        parent::init();

        $this->params['foo'] = 'bar';
        // ...  other initialization code ...
    }
}

如果 init() 方法包含大量初始化模組屬性的程式碼,您也可以將它們以配置的形式儲存,並使用以下程式碼在 init() 中載入它

public function init()
{
    parent::init();
    // initialize the module with the configuration loaded from config.php
    \Yii::configure($this, require __DIR__ . '/config.php');
}

其中配置檔案 config.php 可能包含以下內容,類似於應用程式配置中的內容。

<?php
return [
    'components' => [
        // list of component configurations
    ],
    'params' => [
        // list of parameters
    ],
];

模組中的控制器

在模組中建立控制器時,慣例是將控制器類別放在模組類別命名空間的 controllers 子命名空間下。這也意味著控制器類別檔案應該放在模組基底路徑內的 controllers 目錄中。例如,要在上一個小節中顯示的 forum 模組中建立 post 控制器,您應該像下面這樣宣告控制器類別

namespace app\modules\forum\controllers;

use yii\web\Controller;

class PostController extends Controller
{
    // ...
}

您可以透過配置 yii\base\Module::$controllerNamespace 屬性來自訂控制器類別的命名空間。如果某些控制器位於此命名空間之外,您可以透過配置 yii\base\Module::$controllerMap 屬性使它們可存取,類似於在應用程式中所做的事情

模組中的視圖

模組中的視圖應放在模組基底路徑內的 views 目錄中。對於模組中的控制器呈現的視圖,它們應放在 views/ControllerID 目錄下,其中 ControllerID 指的是控制器 ID。例如,如果控制器類別是 PostController,則目錄將是模組基底路徑內的 views/post

模組可以指定一個佈局,該佈局應用於模組控制器呈現的視圖。佈局預設應放在 views/layouts 目錄中,您應該配置 yii\base\Module::$layout 屬性以指向佈局名稱。如果您未配置 layout 屬性,則將改為使用應用程式的佈局。

模組中的控制台命令

您的模組也可以宣告命令,這些命令將透過控制台模式提供。

為了使命令列公用程式看到您的命令,您需要在控制台模式下執行 Yii 時更改 yii\base\Module::$controllerNamespace 屬性,並將其指向您的命令命名空間。

實現此目的的一種方法是在模組的 init() 方法中測試 Yii 應用程式的實例類型

public function init()
{
    parent::init();
    if (Yii::$app instanceof \yii\console\Application) {
        $this->controllerNamespace = 'app\modules\forum\commands';
    }
}

然後,您的命令將可從命令列使用以下路由

yii <module_id>/<command>/<sub_command>

使用模組

要在應用程式中使用模組,只需透過在應用程式的 modules 屬性中列出模組來配置應用程式。 應用程式配置中的以下程式碼使用了 forum 模組

[
    'modules' => [
        'forum' => [
            'class' => 'app\modules\forum\Module',
            // ... other configurations for the module ...
        ],
    ],
]

資訊:要連接模組的控制台命令,您還需要將其包含在 控制台應用程式配置

modules 屬性接受模組配置的陣列。每個陣列鍵代表一個模組 ID,它唯一地識別應用程式中所有模組中的模組,並且相應的陣列值是用於建立模組的配置

路由

與存取應用程式中的控制器類似,路由用於尋址模組中的控制器。模組內控制器的路由必須以模組 ID 開頭,後跟控制器 ID操作 ID。例如,如果應用程式使用名為 forum 的模組,則路由 forum/post/index 將表示模組中 post 控制器的 index 操作。如果路由僅包含模組 ID,則預設為 defaultyii\base\Module::$defaultRoute 屬性將決定應使用哪個控制器/操作。這表示路由 forum 將表示 forum 模組中的 default 控制器。

模組的 URL 管理器規則應在 yii\web\UrlManager::parseRequest() 觸發之前新增。這表示在模組的 init() 中執行它將不起作用,因為模組將在路由已處理時初始化。因此,規則應在啟動階段新增。將模組的 URL 規則包裝在 yii\web\GroupUrlRule 中也是一個好習慣。

如果模組用於版本化 API,則其 URL 規則應直接新增到應用程式配置的 urlManager 區段中。

存取模組

在模組中,您可能經常需要取得模組類別的實例,以便您可以存取模組 ID、模組參數、模組組件等。您可以使用以下語句來執行此操作

$module = MyModuleClass::getInstance();

其中 MyModuleClass 指的是您感興趣的模組類別的名稱。 getInstance() 方法將傳回目前請求的模組類別的實例。如果未請求模組,則該方法將傳回 null。請注意,您不想手動建立模組類別的新實例,因為它將與 Yii 響應請求而建立的實例不同。

資訊:在開發模組時,您不應假設模組將使用固定的 ID。這是因為當在應用程式中或另一個模組中使用模組時,模組可以與任意 ID 關聯。為了取得模組 ID,您應該使用上述方法首先取得模組實例,然後透過 $module->id 取得 ID。

您也可以使用以下方法存取模組的實例

// get the child module whose ID is "forum"
$module = \Yii::$app->getModule('forum');

// get the module to which the currently requested controller belongs
$module = \Yii::$app->controller->module;

第一種方法僅在您知道模組 ID 時才有用,而第二種方法最適合在您了解正在請求的控制器時使用。

一旦您擁有模組實例,您就可以存取向模組註冊的參數和組件。例如,

$maxPostCount = $module->params['maxPostCount'];

啟動模組

某些模組可能需要在每個請求中執行。yii\debug\Module 模組就是這樣一個範例。為此,請在應用程式的 bootstrap 屬性中列出此類模組的 ID。

例如,以下應用程式配置確保始終載入 debug 模組

[
    'bootstrap' => [
        'debug',
    ],

    'modules' => [
        'debug' => 'yii\debug\Module',
    ],
]

巢狀模組

模組可以巢狀在無限層級中。也就是說,一個模組可以包含另一個模組,而該模組又可以包含另一個模組。我們將前者稱為父模組,而將後者稱為子模組。子模組必須在其父模組的 modules 屬性中宣告。例如,

namespace app\modules\forum;

class Module extends \yii\base\Module
{
    public function init()
    {
        parent::init();

        $this->modules = [
            'admin' => [
                // you should consider using a shorter namespace here!
                'class' => 'app\modules\forum\modules\admin\Module',
            ],
        ];
    }
}

對於巢狀模組中的控制器,其路由應包含其所有祖先模組的 ID。例如,路由 forum/admin/dashboard/index 表示 admin 模組中 dashboard 控制器的 index 操作,該模組是 forum 模組的子模組。

資訊:getModule() 方法僅傳回直接屬於其父模組的子模組。yii\base\Application::$loadedModules 屬性保留已載入模組的清單,包括直接子模組和巢狀子模組,並按其類別名稱索引。

從模組內部存取組件

自 2.0.13 版本起,模組支援樹狀遍歷。這允許模組開發人員透過作為其模組的服務定位器來引用(應用程式)組件。這表示最好使用 $module->get('db') 而不是 Yii::$app->get('db')。如果需要不同的組件(配置),模組的使用者可以指定要用於模組的特定組件。

例如,考慮以下部分應用程式配置

'components' => [
    'db' => [
        'tablePrefix' => 'main_',
        'class' => Connection::class,
        'enableQueryCache' => false
    ],
],
'modules' => [
    'mymodule' => [
        'components' => [
            'db' => [
                'tablePrefix' => 'module_',
                'class' => Connection::class
            ],
        ],
    ],
],

應用程式資料庫表將以 main_ 為前綴,而所有模組表將以 module_ 為前綴。請注意,上面的配置未合併;例如,模組的組件將啟用查詢快取,因為那是預設值。

最佳實踐

模組最適合用於大型應用程式,這些應用程式的功能可以分為幾個組,每個組由一組密切相關的功能組成。每個這樣的功能組都可以開發為模組,由特定的開發人員或團隊開發和維護。

模組也是在功能組層級重用程式碼的好方法。一些常用的功能,例如使用者管理、評論管理,都可以以模組的形式開發,以便可以在未來的專案中輕鬆重用。

發現錯字或您認為此頁面需要改進?
在 github 上編輯它 !